package il.ac.technion.wiki.impl.parsers;

import static org.junit.Assert.*;
import il.ac.technion.wiki.api.expressions.AndOp;
import il.ac.technion.wiki.api.expressions.BinaryOperation;
import il.ac.technion.wiki.api.expressions.Expression;
import il.ac.technion.wiki.api.expressions.NotOp;
import il.ac.technion.wiki.api.expressions.OrOp;
import il.ac.technion.wiki.api.expressions.Term;
import il.ac.technion.wiki.api.expressions.UnaryOperation;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class WikiQueryParserTest {

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testAndParseWitoutParanthesis() {
		String test = "\"new\" and \"york\"";
		Expression ex = new WikiQueryParser().parse(test);
		if (!(ex instanceof AndOp))
			fail("\"and\" is not the root");
		BinaryOperation bo = (BinaryOperation) ex;
		if (!(bo.getFstElement() instanceof Term))
			fail("fst son is not a Term");
		Term fSon = (Term) bo.getFstElement();
		Assert.assertEquals("\"new\" is not the first son", "new",
				fSon.getTerm());

		if (!(bo.getSndElement() instanceof Term))
			fail("snd son is not a Term");
		Term sSon = (Term) bo.getSndElement();
		Assert.assertEquals("\"york\" is not the first son", "york",
				sSon.getTerm());
	}

	@Test
	public void testWitoutArgument() {
		String test = "\"new\" and";
		try {
			new WikiQueryParser().parse(test);
			fail("didn't find missing argument");
		} catch (ArrayIndexOutOfBoundsException e) {
		}
		test = "not";
		try {
			new WikiQueryParser().parse(test);
			fail("didn't find missing argument");
		} catch (ArrayIndexOutOfBoundsException e) {
		}
	}
	
	@Test
	public void testIllegalInput(){
		String test = "new";
		try{
			new WikiQueryParser().parse(test);
			fail("didn't throw excpetion for illegal input");
		} catch (IllegalArgumentException e) {
			System.out.println(e.getMessage());
		}
		test = "\"new\" and york";
		try{
			new WikiQueryParser().parse(test);
			fail("didn't throw excpetion for illegal input");
		} catch (IllegalArgumentException e) {
			System.out.println(e.getMessage());
		}
	}

	@Test
	public void testOrParseWitoutParanthesis() {
		String test = "\"new\" OR \"york\"";
		Expression ex = new WikiQueryParser().parse(test);
		if (!(ex instanceof OrOp))
			fail("\"or\" is not the root");
		BinaryOperation bo = (BinaryOperation) ex;
		if (!(bo.getFstElement() instanceof Term))
			fail("fst son is not a Term");
		Term fSon = (Term) bo.getFstElement();
		Assert.assertEquals("\"new\" is not the first son", "new",
				fSon.getTerm());

		if (!(bo.getSndElement() instanceof Term))
			fail("snd son is not a Term");
		Term sSon = (Term) bo.getSndElement();
		Assert.assertEquals("\"york\" is not the first son", "york",
				sSon.getTerm());		
	}

	@Test
	public void testNotParseWitoutParanthesis() {
		String test = "not \"new\"";
		Expression ex = new WikiQueryParser().parse(test);
		if (!(ex instanceof NotOp))
			fail("\"not\" is not the root");
		UnaryOperation uo = (UnaryOperation) ex;
		if (!(uo.getElement() instanceof Term))
			fail("fst son is not a Term");
		Term expr = (Term) uo.getElement();
		Assert.assertEquals("\"new\" is not the son", "new",
				expr.getTerm());
	}

	 @Test
	public void testBinaryParseWithParanthesis() {
		String test = "\"new\" and (\"york\" or \"mexico\")";
		Expression ex = new WikiQueryParser().parse(test);
		if (!(ex instanceof AndOp))
			fail("\"and\" is not the root");
		BinaryOperation bo = (BinaryOperation) ex;
		if (!(bo.getFstElement() instanceof Term))
			fail("\"and\" fst son is not a Term");
		Term andFSon = (Term) bo.getFstElement();
		Assert.assertEquals("\"new\" is not the first son", "new",
				andFSon.getTerm());
		if (!(bo.getSndElement() instanceof OrOp))
			fail("snd son is not a an \"or\"");
		BinaryOperation bo2 = (BinaryOperation) bo.getSndElement();
		if (!(bo2.getFstElement() instanceof Term))
			fail("\"or\" fst son is not a Term");
		Term orFSon = (Term) bo2.getFstElement();
		Assert.assertEquals("\"york\" is not the first son", "york",
				orFSon.getTerm());
		if (!(bo2.getSndElement() instanceof Term))
			fail("\"or\" snd son is not a Term");
		Term orSSon = (Term) bo2.getSndElement();
		Assert.assertEquals("\"mexico\" is not the snd son", "mexico",
				orSSon.getTerm());
	}

	 @Test
		public void testUnaryParseWithParanthesis() {
			String test = "not (\"new\" or \"york\")";
			Expression ex = new WikiQueryParser().parse(test);
			if (!(ex instanceof NotOp))
				fail("\"not\" is not the root");
			UnaryOperation uo = (UnaryOperation) ex;
			if (!(uo.getElement() instanceof OrOp))
				fail("\"not\" son is not an \"or\" operation");
			BinaryOperation bo = (BinaryOperation) uo.getElement();
			if (!(bo.getFstElement() instanceof Term))
				fail("\"or\" fst son is not a Term");
			Term orFSon = (Term) bo.getFstElement();
			Assert.assertEquals("\"new\" is not the first son", "new",
					orFSon.getTerm());
			if (!(bo.getSndElement() instanceof Term))
				fail("\"or\" snd son is not a Term");
			Term orSSon = (Term) bo.getSndElement();
			Assert.assertEquals("\"york\" is not the snd son", "york",
					orSSon.getTerm());
		}

}
